\section{Conditional Register Updates}

As shown earlier in the tutorial, conditional register updates are performed with the \verb+when+ block which takes a \verb+Bool+ value or some boolean expression to evaluate.
In this section we more fully explore how to use this \verb+when+ conditional update structure.

If a \verb+when+ block is used by itself, Chipper will assume that if the condition for the \verb+when+ block doesn't evaluate to true, there is no update to the register value. However, most of the time we don't want to limit ourselves to a single conditional. Thus in Chipper we use \verb+.elsewhen+ and \verb+.otherwise+ statements to select between multiple possible register updates as shown in the following sections.

\subsection{The {\tt else} {\tt when} Clause}

When specifying a conditional update, we may want to check several conditions which we want to check in some order. 
To do this for register updates, we use a \verb+when ... .elsewhen+ structure. This is analagous to an \verb+if... else if+ control structure in sequential programming. \footnote{Note that the if .. else if control structure in Chipper is NOT used to specify register updates} 
As with \verb+else if+ clauses, as many \verb+.elsewhen+ statements can be chained together in a single \verb+when+ block. 

The general structure thus looks like:

%$when$ (<condition 1>) {<register update 1>}
%.elsewhen (<condition 2>) {<register update 2>}
%...
%.elsewhen (<condition N>) {<register update 3>}

\begin{stanza}
when <condition 1>: <register update 1>
else: when <condition 2> <register update 2>
...
else: when <condition N> <register update N>
\end{stanza}

Where \verb+<condition 1>+ through \verb+<condition N>+ represent the trigger conditions of their respective \verb+<register update>+ segments.

An example of this statement in action is shown in the following implementation of a simple stack pointer. Suppose, we need to maintain a pointer that keeps track of the address of the top of a stack. Given a signal \verb+pop+ that decrements the stack pointer address by 1 entry and a signal \verb+push+ that increments the stack pointer address by 1 entry, the implementation of just the pointer would look like the following:

\begin{stanza}
defmodule StackPointer (depth:Int) :
  input push : Bool
  input en   : Bool
  input pop  : Bool

  reg sp <- UInt<log2Up(depth)>(0)
  
  when io.en && io.push && (sp != UInt(depth-1)) :
    sp := sp + UInt(1)
  else: when io.en && io.pop && (sp > UInt(0)) :
    sp := sp - UInt(1)
\end{stanza}

Notice that in this implementation, the push signal has higher priority over the pop signal as it appears earlier in the \verb+when+ block.

\subsection{The {\tt else} Clause}

In order to specify a default register update value if all the conditions in the \verb+when+ block fail to trigger, we use an \verb+.otherwise+ clause. 
The \verb+else+ clause is analagous to the \verb+else+ case that completes an \verb+if ... else+ block. The \verb+.otherwise+ statement must occur last in the \verb+when+ block.

The general structure for the complete \verb+when+ block now looks like:
\begin{stanza}
when <condition 1>: <register update 1>
else: when <condition 2> <register update 2>
...
else: when <condition N> <register update N>
else: <default register update>
\end{stanza}

In the previous example, we could add a default statement which just assigns \verb+sp+ to the current value of \verb+sp+. The \verb+block+ would then look like:

\begin{stanza}
when io.en && io.push && (sp != UInt(depth-1)) :
  sp := sp + UInt(1)
else: when io.en && io.pop && (sp > UInt(0)) :
  sp := sp - UInt(1)
else: 
  sp := sp
\end{stanza}

The explicit assignment to preserve the value of \verb+sp+ is redundant in this case but it captures the point of the \verb+.otherwise+ statement.

\subsection{The {\tt unless} Clause}

% Martin: this feels a little bit strange as it is not a usual construct in a programming language.
% It is simple !condition, right? So I would drop it.

To complement the \verb+when+ statement, Chipper also supports an \verb+unless+ statement. The \verb+unless+ statement is a conditional assignment that triggers only if the condition is false. The general structure for the \verb+unless+ statement is:

\begin{stanza}
unless <condition>: <assignments>
\end{stanza}

For example, suppose we want to do a simple search of the contents of memory and determine the address that contains some number. Since we don't know how long the search will take, the module will output a \verb+done+ signal when it is finished and until then, we want to continue to search memory. The Chipper code for the module would look like:

\begin{stanza}
defmodule MemorySearch (depth:Int) :
  input  address: UInt<3>
  input  target:  UInt<4>
  input  en:      Bool
  output done:    Bool

  val inits = [0, 4, 15, 14, 2, 5, 13]
  wire vals: UInt<4>[7]
  for i in 0 to length(inits) do:
    vals[i] := UInt(inits[i])
  reg index : UInt<4>
  wire elt    = vals[index]
  wire isDone = ! en & ((elt === target) | (index === UInt(7)))
  when en :
    index := UInt(0)
  else when ! isDone :
    index := index + UInt(1)
  done    := isDone
  address := index
\end{stanza}

In this example, we limit the size of the memory to 8 entries and use a vector of literals to create a read only memory. Notice that the \verb+unless+ statement is used to terminate the iteration if it see that the \verb+done+ signal is asserted. Otherwise, it will continue to increment the index in memory until it finds the value in \verb+target+ or reaches the last index in the memory (7).

\section{Combinational Conditional Assignment}

You can also use the \verb+when .elsewhen .otherwise+ block to define combinational values that may take many values. For example, the following Chipper code show how to implement a basic arithmetic unit with 4 operations: add, subtract, and pass. In this example, we check the opcode to determine which operation to perform and conditionally assign the output.

\begin{stanza}
class BasicALU extends Module {
  input  a      : UInt<4>
  input  b      : UInt<4>
  input  opcode : UInt<4>
  output output : UInt<4>
  }
  output := UInt(0) 
  when opcode === UInt(0) :
    output := a                   ;; pass A
  else: 
    output := b                   ;; pass B
\end{stanza}

Notice that this can easily be easily expanded to check many different conditions for more complicated arithmetic units or combinational blocks.

\section{Read Only Memories}

To instantiate read only memories in Chipper, we use a vector of constant literals and specify a literal type. For example, in order to instantiate an 4 entry read only memory with the values 0 to 3, the definition would look like the following:

\begin{footnotesize}
\begin{stanza}
wire numbers : UInt<2>[4]
for i in 0 to 4 do :
  numbers[i] := UInt(i)
\end{stanza}
\end{footnotesize}

Notice that we need to specify the type of literal in the {...} braces following the literals. Accessing the values in the read only memory is the same as accessing an entry in a \verb+Vec+. For example, to access the 2nd entry of the memory we would use:

\begin{stanza}
wire entry2 = numbers[2]
\end{stanza}

\section{Read-Write Memories}

Chipper contains a primitive for memories called \verb+Mem+. Using the \verb+Mem+ class it is possible to construct multi-ported memory that can be synchronous or combinational read. \footnote{The complete definition can be found in the chipper source in  Mem.stanza}

\subsection{Basic Instantiation}

The \verb+Mem+ construction takes a memory depth and a data type which it is composed of. The general declaration structure looks like:

\begin{stanza}
mem myMem : <type>[<depth>]
\end{stanza}

Where \verb+<depth>+ corresponds to the number of entries of \verb+<type>+ are in the memory.

For instance, if you wanted to create a 128 deep memory of 32 bit UInt types, you would use the following instantiation:

\begin{stanza}
mem myMem UInt<32>[128]
\end{stanza}

Note that when constructing a memory in Chipper, the initial value of memory contents cannot be specified. Therefore, you should never assume anything about the initial contents of your \verb+Mem+ class.

\subsection{Synchronous vs. Combinational Read}

It is possible to specify either combinational or synchronous read behavior during instantiation by setting the \verb+seqRead+ parameter when defining the \verb+Mem+. The \verb+seqRead+ parameter is a \verb+Bool+ that tells Chipper if you want synchronous read behavior memory or not.

For instance, if we wanted a combinational read 128 entry memory of 32 bit UInt types, we would use the following definition:

\begin{stanza}
mem asyncMem : UInt<32>[128]
\end{stanza}

Likewise, if we wanted a synchronous read 128 entry memory of 32 bit UInt types, we would set the \verb+seqRead+ to true:

\begin{stanza}
seqmem syncMem : UInt<32>[128]
\end{stanza}

% this needs more elaboration. Memories in hardware are tough...

By default, Chipper will assume that the read behavior is combinational.

\subsection{Adding Write Ports}

To add write ports to the \verb+Mem+, we use a \verb+when+ block to allow Chipper to infer a write port. Inside the \verb+when+ block, we specify the location and data for the write transaction. In general, adding a write port requires the following definition:

\begin{stanza}
when <write condition> :
  <memory name>[ <write address> ] := <write data>
\end{stanza}

Where \verb+<write address>+ refers to the entry number in the memory to write to. Also notice that we use the reassignment operator \verb+:=+ when writing to the memory. 


For example, suppose we have a 128 deep memory of 32 bit UInt types. If we wanted to write a 32 bit value \verb+dataIn+ to the memory at location \verb+writeAddr+ if as write enable signal \verb+we+ is true, our Chipper code would look like:

\begin{stanza}
...
mem myMem : UInt<32>[128]
when wen :
  myMem[writeAddr] := dataIn
...
\end{stanza}

<what is the behavior of multiple write ports?>

\subsection{Adding Read Ports}

Depending on the type of read behaviour specified, the syntax for adding read ports to \verb+Mem+ in Chipper is slightly different for combinational read and synchronous read memories.

\subsubsection{Combinational Read Ports}

For combinational read memories, adding read ports to the memory simply amounts to placing an assignment inside a \verb+when+ block with some trigger condition. If you want Chipper to infer multiple read ports, simply add more assignments in the \verb+when+ definition. The general definition for read ports is thus:

\begin{stanza}
when <read condition> :
  <read data 1> := <memory name>[ <read address 1> ]
  ...
  <read data N> := <memory name>[ <read address N> ]
\end{stanza}

For instance, if you wanted a 128 entry memory of 32 bit UInt values with two combinational read ports, with some read enable \verb+re+ and reads from addresses \verb+raddr1+ and \verb+raddr2+, we would use the following \verb+when+ block definition:

\begin{stanza}
...
mem myMem : UInt<32>[128]
wire read_port1 : UInt<32>
wire read_port2 : UInt<32>
when re :
  read_port1 := myMem[raddr1]
  read_port2 := myMem[raddr2]
...
\end{stanza}

Note that the type and width of the \verb+read_port1+ and \verb+read_port2+ should match the type and width of the entries in the \verb+Mem+.

\subsubsection{Synchronous Read Ports}

In order to add synchronous read ports to the Chipper \verb+Mem+ class, Chipper requires that the output from the memory be assigned to a \verb+Reg+ type. Like the combinational read port, a synchronous read assignment must occur in a \verb+when+ block. The general structure for the definition of a synchronous read port is as follows:

\begin{stanza}
...
seqmem myMem : UInt<32>[128]
wire read_port : UInt<32>
when re :
  read_port := myMem[raddr]
...
\end{stanza}

\subsection{Example of Mem in Action}

% Martin: no, it was not yet shown
%We introduced a basic stack pointer bookkeeping example earlier in the tutorial. In this section we show how the complete stack implementation would look like.

Here we provide a small example of using a memory by implementing a stack.

Suppose we would like to implement a stack that takes two signals \verb+push+ and \verb+pop+ where \verb+push+ tells the stack to push an input \verb+dataIn+ to the top of the stack, and \verb+pop+ tells the stack to pop off the top value from the stack. Furthermore, an enable signal \verb+en+ disables pushing or popping if not asserted. Finally, the stack should always output the top value of the stack.

\begin{stanza}
defmodule Stack (depth:Int) :
  input push: UInt<1>
  input pop: UInt<1>
  input en: UInt<1>
  input dataIn: UInt<32>
  output dataOut: UInt<32>

  mem stack_mem : UInt<32>[depth]
  reg sp : UInt<sizeof(depth)> sp := UInt(0)
  wire out : UInt<32> out := UInt(0)

  when en :
    when push & (sp < UInt(depth)) :
      stack_mem[sp] := dataIn
      sp := sp + UInt(1)
    else when pop & (sp > UInt(0)) :
      sp := sp - UInt(1)
    when sp > UInt(0) :
      out := stack_mem[sp - UInt(1)]

  dataOut := out
\end{stanza}

Since the module is parametrized to be \verb+depth+ entries deep, in order to correctly extract the minimum width of the stack pointer \verb+sp+ we take the \verb+log2Up(depth)+. This takes the base 2 logarithm of \verb+depth+ and rounds up.

\subsection{\problem{Load/Search Mem}}

In this assignment, write a memory module that supports loading elements and searching based on the following template:

\begin{stanza}
defmodule MemorySearch (depth:Int, w:Int) :
  input  target: UInt<4>
  input  wrAddr: UInt<log2Up(depth)>
  input  data:   UInt<w>
  input  en:     Bool
  input  isWr:   Bool
  output done:   Bool
  output addr:   UInt<log2Up(depth)>

  reg index : UInt<log2Up(depth)> <- UInt(0)
  wire memVal = UInt(0)
  done := Bool(false)
  addr := index
\end{stanza}

\noindent
and found in \verb+$TUT_DIR/problems/DynamicMemorySearch.stanza+.
Notice how it support depth and width parameters \verb+n+ and \verb+w+ and 
how the address width is computed from the depth. Run 

\begin{bash}
make DynamicMemorySearch.out
\end{bash}

\noindent 
until your circuit passes the tests.
